Ext.ns('Ext.ux.form');
/**
 * 时间选择器
 * @class Ext.ux.form.TimePickerField
 * @extends Ext.form.Field
 * @constructor
 * @param {object} config
 */
Ext.ux.form.TimePickerField = function(config){
    Ext.ux.form.TimePickerField.superclass.constructor.call(this, config);
}
/*
 * 继承 {@link Ext.form.Field} 并添加自定义属性方法
 * @extend Ext.form.Field
 */
Ext.extend(Ext.ux.form.TimePickerField, Ext.form.Field, {
    defaultAutoCreate: {
        tag: 'div'// 定义了一个DIV标签
    },
    cls: 'x-form-timepickerfield',// 它的样式
    hoursSpinner: null,// 属性：小时选择器
    minutesSpinner: null,// 属性：分钟选择器
    secondsSpinner: null,// 属性：秒选择器
    spinnerCfg: {
        width: 40// 选择器的宽度定位40px
    },
	
	// 约束：选择数值约束，如果小于最小值该如何，如果大于最大值该如何，这里的处理方式我详细说明一下
    // （这个约束是触发的，我们输入的值或者我们点击上下箭头选择的值后都会进入该约束检查。）
    spinnerFixBoundries: function(value){
		// 这里有可能会造成不解，我解释一下。
		// 如果我们选择秒的时候，有一个向上的箭头和向下的箭头，如果我点击向上的箭头则秒数加1，点击向下的箭头则秒数减1。
		// 如果我选择了59秒后，点击向上的箭头，由于时间秒数约束，不可能出现60，那我们要怎么办？会如何？当然是，58,59,0,1这样的序列
		// 所以最大值定义为59，如果超过59那么秒数归零，就是这个逻辑。
        if (value < this.field.minValue) {
            value = this.field.maxValue;
        }
        if (value > this.field.maxValue) {
            value = this.field.minValue;
        }
		// 这里返回了一个带有精度的值
        return this.fixPrecision(value);
    },
	// 渲染，这个没什么可说的了所有的渲染都差不多是位置和范围之类的
    onRender: function(ct, position){
        Ext.ux.form.TimePickerField.superclass.onRender.call(this, ct, position);
        this.rendered = false;
        this.date = new Date();
		// 定义一个对象，他即将有三个属性，时分秒数值，往下看。
        var values = {};
		// 如果实例时已经被设定了初始值，那么将这些值赋予values这个对象中。
		// 再将这些值表示在时分秒选择器中
        if (this.value) {
            values = this._valueSplit(this.value);
            this.date.setHours(values.h);
            this.date.setMinutes(values.m);
            this.date.setSeconds(values.s);
            delete this.value;
        }
		// 如果实例时没被设定了初始值，简单了，时分秒选择器的初始值就不用改变了，只要values得到这些值备用即可
        else {
            values = {
                h: this.date.getHours(),
                m: this.date.getMinutes(),
                s: this.date.getSeconds()
            };
        }
		// 定义一个外围包裹，就是想把时分秒这三个选择器给包起来成为一组，下面会实例这三个选择器的，往下看。
        var spinnerWrap = Ext.DomHelper.append(this.el, {
            tag: 'div'
        });
        var cfg = Ext.apply({}, this.spinnerCfg, {
            renderTo: spinnerWrap,
            readOnly: this.readOnly,
            disabled: this.disabled,
            listeners: {
                spin: {
                    fn: this.onSpinnerChange,
                    scope: this
                },
                valid: {
                    fn: this.onSpinnerChange,
                    scope: this
                },
                afterrender: {
                    fn: function(spinner){
                        spinner.wrap.applyStyles('float: left');
                    },
                    single: true
                }
            }
        });
		// 接下来实例（Ext.ux.form.SpinnerField）了几个选择器，时分秒。
        this.hoursSpinner = new Ext.ux.form.SpinnerField(Ext.apply({}, cfg, {
            minValue: 0,
            maxValue: 23,
            cls: 'first',
            value: values.h
        }));
        this.minutesSpinner = new Ext.ux.form.SpinnerField(Ext.apply({}, cfg, {
            minValue: 0,
            maxValue: 59,
            value: values.m
        }));
        this.secondsSpinner = new Ext.ux.form.SpinnerField(Ext.apply({}, cfg, {
            minValue: 0,
            maxValue: 59,
            value: values.s
        }));
        Ext.DomHelper.append(spinnerWrap, {
            tag: 'div',
            cls: 'x-form-clear-left'
        });
		// 渲染完毕释放出去
        this.rendered = true;
    },
	// 如果实例时已经被设定了初始值，那么调用这个方法，将这些值赋予values这个对象中。
    _valueSplit: function(v){
        var split = v.split(':');
        return {
            h: split.length > 0 ? split[0] : 0,
            m: split.length > 1 ? split[1] : 0,
            s: split.length > 2 ? split[2] : 0
        };
    },
	// 注意了，这里加了一个动作的监听，也可以说是自己弄了一个自定义监听
    onSpinnerChange: function(){
        if (!this.rendered) {
            return;
        }
		// 这里注册了这个监听类别，指明了监听的对象
        this.fireEvent('change', this, this.getRawValue());
    },
	// 禁用
    disable: function(){
        Ext.ux.form.TimePickerField.superclass.disable.call(this);
        this.hoursSpinner.disable();
        this.minutesSpinner.disable();
        this.secondsSpinner.disable();
    },
	// 解用
    enable: function(){
        Ext.ux.form.TimePickerField.superclass.enable.call(this);
        this.hoursSpinner.enable();
        this.minutesSpinner.enable();
        this.secondsSpinner.enable();
    },
	// 只读
    setReadOnly: function(r){
        Ext.ux.form.TimePickerField.superclass.setReadOnly.call(this, r);
        this.hoursSpinner.setReadOnly(r);
        this.minutesSpinner.setReadOnly(r);
        this.secondsSpinner.setReadOnly(r);
    },
	// 清除所有的无效验证
    clearInvalid: function(){
        Ext.ux.form.TimePickerField.superclass.clearInvalid.call(this);
        this.hoursSpinner.clearInvalid();
        this.minutesSpinner.clearInvalid();
        this.secondsSpinner.clearInvalid();
    },
	// 拿到那个值，可以认为是vlaues对象
    getRawValue: function(){
        if (!this.hoursSpinner) {
            this.date = new Date();
            return {
                h: this.date.getHours(),
                m: this.date.getMinutes(),
                s: this.date.getSeconds()
            };
        }
        else {
            return {
                h: this.hoursSpinner.getValue(),
                m: this.minutesSpinner.getValue(),
                s: this.secondsSpinner.getValue()
            };
        }
    },
	// 赋值
    setRawValue: function(v){
        this.hoursSpinner.setValue(v.h);
        this.minutesSpinner.setValue(v.m);
        this.secondsSpinner.setValue(v.s);
    },
	// 有效验证
    isValid: function(preventMark){
        return this.hoursSpinner.isValid(preventMark) &&
        this.minutesSpinner.isValid(preventMark) &&
        this.secondsSpinner.isValid(preventMark);
    },
	// 验证
    validate: function(){
        return this.hoursSpinner.validate() &&
        this.minutesSpinner.validate() &&
        this.secondsSpinner.validate();
    },
	// 这里可以自己修改想要的格式，这个值将作为返回值到调用该类的元控件中也就是DateTimeField的实例
    getValue: function(){
        var v = this.getRawValue();
        return String.leftPad(v.h, 2, '0') + ':' +
        String.leftPad(v.m, 2, '0') +
        ':' +
        String.leftPad(v.s, 2, '0');
    },
    setValue: function(value){
        if (!this.rendered) {
            this.value = value;
            return;
        }
        value = this._valueSplit(value);
        this.setRawValue(value);
        this.validate();
    }
});

Ext.form.TimePickerField = Ext.ux.form.TimePickerField;
Ext.reg('timepickerfield', Ext.form.TimePickerField);